package hotciv.variants;

import java.util.ArrayList;

import hotciv.common.*;
import hotciv.framework.*;
import hotciv.strategies.AttackStrategy;


public class EpsilonCivAttackStrategy implements AttackStrategy {

	ModifiableGame game;
	DieRoller dr;

	public EpsilonCivAttackStrategy(DieRoller dr) {
		this.dr = dr;
	}
	
	public EpsilonCivAttackStrategy() {
		this(new RandomDieRoller());
	}
	
	@Override
	public boolean calculateOutcome(ModifiableGame game, Position attPos, Position defPos) {
		this.game = game;
		
		// Gets the strength from the unit, subsidiary the AttackAndDefensiveStrategy
		int attackUnitStrength = game.getUnitAt(attPos).getAttackingStrength();
		int defendUnitStrength = game.getUnitAt(defPos).getDefensiveStrength();

		attackUnitStrength = (attackUnitStrength + friendlyUnitSupport(attPos)) * terrainBonus(attPos);
		defendUnitStrength = (defendUnitStrength + friendlyUnitSupport(defPos)) * terrainBonus(defPos);
		
		// Randomize the strength, based on a random die roll.
		int finalAttStr = attackUnitStrength * rollDie();
		int finalDefStr = defendUnitStrength * rollDie();
		
		// Return the boolean whether the caller wins or looses.
		return (finalAttStr >= finalDefStr);
	}
		

	/**
	 * Calculates the EpsilonCiv specific strategy for boosted strength
	 * that comes from adjacent units
	 * @param p the position of the Player
	 * @return The boost in strength as an integer value
	 */
	private int friendlyUnitSupport(Position p) {
		
		// Put adjacent units in a list
		ArrayList<Unit> adjUnits = new ArrayList<Unit>();
		
		Unit uN,uNE,uE,uSE,uS,uSW,uW,uNW;		
		if((uN 	= game.getUnitAt(p.goNorth())) 		!= null) adjUnits.add(uN);
		if((uNE = game.getUnitAt(p.goNorthEast()))	!= null) adjUnits.add(uNE);
		if((uE 	= game.getUnitAt(p.goEast())) 		!= null) adjUnits.add(uE);
		if((uSE = game.getUnitAt(p.goSouthEast())) 	!= null) adjUnits.add(uSE);
		if((uS 	= game.getUnitAt(p.goSouth())) 		!= null) adjUnits.add(uS);
		if((uSW = game.getUnitAt(p.goSouthWest())) 	!= null) adjUnits.add(uSW);
		if((uW 	= game.getUnitAt(p.goWest())) 		!= null) adjUnits.add(uW);
		if((uNW = game.getUnitAt(p.goNorthWest()))	!= null) adjUnits.add(uNW);
		
		// Iterate through the list and count the number of friendly units
		int bonus = 0;
		Player attPla = game.getUnitAt(p).getOwner();
		for (Unit u : adjUnits) {
			if (u.getOwner() == attPla) {
				bonus += 1;
			}
		}
		
		return bonus;
	}
	
	
	/**
	 * Calculates the EpsilonCiv specific strategy for boosted strength
	 * that comes from either being in a city or on elevated terrain.
	 * @param p the position of the Player
	 * @return The boost in strength as an integer value
	 */
	private int terrainBonus(Position p) {
		City c = game.getCityAt(p);
		if (c != null) return 3;
		
		Tile t = game.getTileAt(p);
		if (t.getTypeString() == GameConstants.HILLS) return 2;
		if (t.getTypeString() == GameConstants.FOREST) return 2;
		
		return 1; // Else no bonus
	}
	

	private int rollDie() {
		return dr.rollDie();
	}
	

}
